home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Utilities / Programming / EnterAct 3.5 / hAWK project / AWK Source / NODE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-22  |  7.6 KB  |  384 lines  |  [TEXT/TOPC]

  1. /*
  2.  * node.c -- routines for node management
  3.  */
  4.  
  5. /* Copyright © 1986, 1988, 1989 1991 the Free Software Foundation, Inc.
  6.  *         This file is part of GAWK, the GNU implementation of the
  7.  * AWK Progamming Language, modified for the Macintosh (also called hAWK).
  8.  *         GAWK is free software; you can redistribute or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 1, or any later version.
  11.  *         GAWK is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14.  * GNU General Public License for more details.
  15.  *         You should have received a copy of the GNU General Public License
  16.  * along with GAWK; see the file "COPYING hAWK". If not, write to
  17.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  * Slightly modified for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
  19.  */
  20. #include "AWK.H"
  21.  
  22. /*extern double strtod();*/
  23.  
  24. /*NODE.C*/
  25. AWKNUM r_force_number(NODE *n);
  26. NODE *r_force_string(NODE *s);
  27. NODE *dupnode(NODE *n);
  28. NODE *make_number(AWKNUM x);
  29. NODE *tmp_number(AWKNUM x);
  30. NODE *make_str_node(char *s, short len, short scan);
  31. static short group_tag_etc(char *p);
  32. NODE *tmp_string(char *s, short len);
  33. NODE *newnode(NODETYPE ty);
  34. void freenode(NODE *it);
  35. void do_deref(void);
  36.  
  37. /*
  38.  * We can't dereference a variable until after we've given it its new value.
  39.  * This variable points to the value we have to free up 
  40.  */
  41. NODE *deref; /* inited in main */
  42.  
  43. AWKNUM r_force_number(NODE *n)
  44. {
  45.     char *ptr;
  46.  
  47. #ifdef DEBUG
  48.     if (n == NULL)
  49.         cant_happen();
  50.     if (n->type != Node_val)
  51.         cant_happen();
  52.     if(n->flags == 0)
  53.         cant_happen();
  54.     if (n->flags & NUM)
  55.         return n->numbr;
  56. #endif
  57.     if (n->stlen == 0)
  58.         n->numbr = 0.0;
  59.     else if (n->stlen == 1) {
  60.         if (isdigit(n->stptr[0])) {
  61.             n->numbr = n->stptr[0] - '0';
  62.             n->flags |= NUMERIC;
  63.         } else
  64.             n->numbr = 0.0;
  65.     } else {
  66.         errno = 0;
  67.         n->numbr = (AWKNUM) strtod(n->stptr, &ptr);
  68.         /* the following >= should be ==, but for SunOS 3.5 strtod() */
  69.         if (errno == 0 && ptr >= n->stptr + n->stlen)
  70.             n->flags |= NUMERIC;
  71.     }
  72.     n->flags |= NUM;
  73.     return n->numbr;
  74. }
  75.  
  76. /*
  77.  * the following lookup table is used as an optimization in force_string
  78.  * (more complicated) variations on this theme didn't seem to pay off, but 
  79.  * systematic testing might be in order at some point
  80.  */
  81. /* This way OK in an application...
  82. static char *values[] = {
  83.     "0",
  84.     "1",
  85.     "2",
  86.     "3",
  87.     "4",
  88.     "5",
  89.     "6",
  90.     "7",
  91.     "8",
  92.     "9"
  93. };
  94. */
  95. /* ..but in a THINK C code resource we need...*/
  96. static char *values[10];
  97. static void InitNumberValues(void);
  98. static void InitNumberValues()
  99.     {
  100.     values[0] = "0";
  101.     values[1] = "1";
  102.     values[2] = "2";
  103.     values[3] = "3";
  104.     values[4] = "4";
  105.     values[5] = "5";
  106.     values[6] = "6";
  107.     values[7] = "7";
  108.     values[8] = "8";
  109.     values[9] = "9";
  110.     }
  111.  
  112. #define    NVAL    (sizeof(values)/sizeof(values[0]))
  113.  
  114. NODE *r_force_string(NODE *s)
  115. {
  116.     char buf[128];
  117.     char *fmt;
  118.     long num;
  119.     char *sp = buf;
  120.  
  121. #ifdef DEBUG
  122.     if (s == NULL)
  123.         cant_happen();
  124.     if (s->type != Node_val)
  125.         cant_happen();
  126.     if (s->flags & STR)
  127.         return s;
  128.     if (!(s->flags & NUM))
  129.         cant_happen();
  130.     if (s->stref != 0)
  131.         cant_happen();
  132. #endif
  133.     s->flags |= STR;
  134.     /* should check validity of user supplied OFMT */
  135.     fmt = OFMT_node->var_value->stptr;
  136.     if ((num = s->numbr) == s->numbr) {
  137.         /* integral value */
  138.         if (num < NVAL && num >= 0) {
  139.             sp = values[num];
  140.             s->stlen = 1;
  141.         } else {
  142.             (void) sprintf(sp, "%ld", num);
  143.             s->stlen = strlen(sp);
  144.         }
  145.     } else {
  146.         (void) sprintf(sp, fmt, s->numbr);
  147.         s->stlen = strlen(sp);
  148.     }
  149.     s->stref = 1;
  150.     emalloc(s->stptr, char *, s->stlen + 1, "force_string");
  151.     memcpy(s->stptr, sp, s->stlen+1);
  152.     return s;
  153. }
  154.  
  155. /*
  156.  * Duplicate a node.  (For strings, "duplicate" means crank up the
  157.  * reference count.)
  158.  */
  159. NODE *dupnode(NODE *n)
  160. {
  161.     register NODE *r;
  162.  
  163.     if (n->flags & TEMP) {
  164.         n->flags &= ~TEMP;
  165.         n->flags |= MALLOC;
  166.         return n;
  167.     }
  168.     if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) {
  169.         if (n->stref < 255)
  170.             n->stref++;
  171.         return n;
  172.     }
  173.     r = newnode(Node_illegal);
  174.     *r = *n;
  175.     r->flags &= ~(PERM|TEMP);
  176.     r->flags |= MALLOC;
  177.     if (n->type == Node_val && (n->flags & STR)) {
  178.         r->stref = 1;
  179.         emalloc(r->stptr, char *, r->stlen + 1, "dupnode");
  180.         memcpy(r->stptr, n->stptr, r->stlen+1);
  181.     }
  182.     return r;
  183. }
  184.  
  185. /* this allocates a node with defined numbr */
  186. NODE *make_number(AWKNUM x)
  187. {
  188.     register NODE *r;
  189.  
  190.     r = newnode(Node_val);
  191.     r->numbr = x;
  192.     r->flags |= (NUM|NUMERIC);
  193.     r->stref = 0;
  194.     return r;
  195. }
  196.  
  197. /*
  198.  * This creates temporary nodes.  They go away quite quickly, so don't use
  199.  * them for anything important 
  200.  */
  201. NODE *tmp_number(AWKNUM x)
  202. {
  203.     NODE *r;
  204.  
  205.     r = make_number(x);
  206.     r->flags |= TEMP;
  207.     return r;
  208. }
  209.  
  210. /*
  211.  * Make a string node.
  212.  */
  213.  
  214. NODE *make_str_node(char *s, short len, short scan)
  215. {
  216.     register NODE *r;
  217.     char *pf;
  218.     register char *pt;
  219.     register short c;
  220.     register char *end;
  221.  
  222.     r = newnode(Node_val);
  223.     emalloc(r->stptr, char *, len + 1, s);
  224.     memcpy(r->stptr, s, len);
  225.     r->stptr[len] = '\0';
  226.     end = &(r->stptr[len]);
  227.            
  228.     if (scan) {    /* scan for escape sequences */
  229.         for (pf = pt = r->stptr; pf < end;) {
  230.             c = *pf++;
  231.             if (c == '\\' && !group_tag_etc(pf)) {
  232.                 c = parse_escape(&pf);
  233.                 if (c < 0)
  234.                     cant_happen();
  235.                 *pt++ = c;
  236.             } else
  237.                 *pt++ = c;
  238.         }
  239.         len = pt - r->stptr;
  240.         erealloc(r->stptr, char *, len + 1, "make_str_node");
  241.         r->stptr[len] = '\0';
  242.         r->flags |= PERM;
  243.     }
  244.     r->stlen = len;
  245.     r->stref = 1;
  246.     r->flags |= (STR|MALLOC);
  247.  
  248.     return r;
  249. }
  250.  
  251. static short group_tag_etc(char *p)
  252.     {
  253.     char theChar = *p;
  254.     
  255.     if (theChar >= '1' && theChar <= '9' && !(*(p+1) >= '0' && *(p+1) <= '7'))
  256.         return 1;
  257.     /* special characters for regular expressions, which must have
  258.     an escaping backslash before: w W < > b B
  259.     */
  260.     if (theChar == 'w' || theChar == 'W' || theChar == '<' || theChar == '>'
  261.         || theChar == 'b' || theChar == 'B')
  262.         return 1;
  263.     return 0;
  264.     }
  265.  
  266. /* Read the warning under tmp_number */
  267. NODE *tmp_string(char *s, short len)
  268. {
  269.     register NODE *r;
  270.  
  271.     r = make_string(s, len);
  272.     r->flags |= TEMP;
  273.     return r;
  274. }
  275.  
  276.  
  277. #define NODECHUNK    100
  278.  
  279. static NODE *nextfree = NULL;
  280.  
  281. NODE *newnode(NODETYPE ty)
  282. {
  283.     NODE *it;
  284.     NODE *np;
  285.  
  286. #ifdef MPROF
  287.     emalloc(it, NODE *, sizeof(NODE), "newnode");
  288. #else
  289.     if (nextfree == NULL) {
  290.         /* get more nodes and initialize list */
  291.         emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
  292.         for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
  293.             np->nextp = np + 1;
  294.         np->nextp = NULL;
  295.     }
  296.     /* get head of freelist */
  297.     it = nextfree;
  298.     nextfree = nextfree->nextp;
  299. #endif
  300.     it->type = ty;
  301.     it->flags = MALLOC;
  302. #ifdef MEMDEBUG
  303.     fprintf(stderr, "node: new: %0x\n", it);
  304. #endif
  305.     return it;
  306. }
  307.  
  308. void freenode(NODE *it)
  309. {
  310. #ifdef DEBUG
  311.     NODE *nf;
  312. #endif
  313. #ifdef MEMDEBUG
  314.     fprintf(stderr, "node: free: %0x\n", it);
  315. #endif
  316. #ifdef MPROF
  317.     free((char *) it);
  318. #else
  319. #ifdef DEBUG
  320.     for (nf = nextfree; nf; nf = nf->nextp)
  321.         if (nf == it)
  322.             fatal("attempt to free free node");
  323. #endif
  324.     /* add it to head of freelist */
  325.     it->nextp = nextfree;
  326.     nextfree = it;
  327. #endif
  328. }
  329.  
  330. #ifdef DEBUG
  331. pf()
  332. {
  333.     NODE *nf = nextfree;
  334.     while (nf != NULL) {
  335.         fprintf(stderr, "%0x ", nf);
  336.         nf = nf->nextp;
  337.     }
  338. }
  339. #endif
  340.  
  341. void do_deref()
  342. {
  343.     if (deref == NULL)
  344.         return;
  345.     if (deref->flags & PERM) {
  346.         deref = 0;
  347.         return;
  348.     }
  349.     if ((deref->flags & MALLOC) || (deref->flags & TEMP)) {
  350.         deref->flags &= ~TEMP;
  351.         if (deref->flags & STR) {
  352.             if (deref->stref > 1 && deref->stref != 255) {
  353.                 deref->stref--;
  354.                 deref = 0;
  355.                 return;
  356.             }
  357.             free(deref->stptr);
  358.         }
  359.         freenode(deref);
  360.     }
  361.     deref = 0;
  362. }
  363.  
  364. void InitNode(void);
  365.  
  366. void InitNode()
  367.     {
  368.     nextfree = NULL;
  369.     if (!hAWKstackDepth)
  370.         InitNumberValues();
  371.     }
  372.  
  373. void SaveNode(void);
  374. void RestoreNode(void);
  375. void SaveNode()
  376.     {
  377.     hs->nextfree = nextfree;
  378.     }
  379.  
  380. void RestoreNode()
  381.     {
  382.     nextfree = hs->nextfree;
  383.     }
  384.